#ifndef UDP_SEVER_HPP
#define UDP_SEVER_HPP

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<queue>
#include"log.hpp"

#define SIZE 1024

class UdpSever
{
public:
    UdpSever(uint16_t port, std::string ip = "")
    :_port(port)
    ,_ip(ip)
    {}

    bool InitSever()
    {
        //实现网络功能的步骤：
        //1.创建套接字
        _sock = socket(AF_INET, SOCK_DGRAM, 0);

        if(_sock < 0)
        {
            logMessage(FATAL, "%d:%s", errno, strerror(errno));
            exit(2);
        }

        //将ip和port与刚创建的套接字绑定
        //bind: 将用户设置的ip和port在内核中和我们当前的进程强关联
        // "192.168.110.132" -> 点分十进制字符串风格的IP地址
        // 每一个区域取值范围是[0-255]: 1字节 -> 4个区域
        // 理论上，表示一个IP地址，其实4字节就够了！！
        // 点分十进制字符串风格的IP地址 <-> 4字节
        struct sockaddr_in local;
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;
        //服务器的ip和port未来也要发送给对方主机，所以要把数据转成网络序列先发送到网络
        local.sin_port = htons(_port);
        // 1. 同上，先要将点分十进制字符串风格的IP地址 ->  4字节
        // 2.  4字节主机序列 -> 网络序列
        // 有一套接口，可以一次帮我们做完这两件事情, 让服务器在工作过程中，可以从任意IP中获取数据
        local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());
        if(bind(_sock, (struct sockaddr*)&local, sizeof(local)) < 0)
        {
            logMessage(FATAL, "%d:%s", errno, strerror(errno)); 
            exit(2);
        }
        logMessage(NORMAL, "init udp server done ... %s", strerror(errno));
        // done
        return true;
    }

    void Start()
    {
        //服务器是永远不退出的
        //服务器运行之后也就是一个进程，我们把这种一直在内存中存在，除非挂了否则不退出的进程称为常驻进程
        char buffer[SIZE];
        for(;;)
        {
            //peer 纯输出型参数
            struct sockaddr_in peer;
            bzero(&peer, sizeof(peer));
            //输入：peer缓冲区大小
            //输出：实际读到的peer
            socklen_t len = sizeof(peer);
            //char result[256];
            //char key[64];
            //std::string cmd_echo;
            //读取数据
            ssize_t s = recvfrom(_sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&peer, &len);
            if(s > 0)
            {
                //1.echo sever 用户端发什么都不做处理直接发回去
                uint16_t cli_port = ntohs(peer.sin_port);
                std::string cli_ip = inet_ntoa(peer.sin_addr);
                printf("[%s : %d]# %s\n", cli_ip.c_str(), cli_port, buffer);
                sendto(_sock, buffer, strlen(buffer), 0, (struct sockaddr*)&peer, len); 

            }
            else
            {
                logMessage(ERROR, "%s", "no receive");
            }
        }
    }

    ~UdpSever()
    {
        if(_sock >= 0)
        {
            close(_sock);
        }
    }



private:
    uint16_t _port;
    std::string _ip;
    int _sock;
};


#endif